/* 
 * Rug.Cmd part of Rugland Console Framework
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * Copyright (C) 2008 Phill Tew. All rights reserved.
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;

namespace Rug.Cmd.Colors
{
	#region Console Color Default Themes

	/// <summary>
	/// Built in color themes. 
	/// </summary>
	public enum ConsoleColorDefaultThemes
	{
		/// <summary>
		/// No theme
		/// </summary>
		None = 0,   
		
		/// <summary>
		/// High contrast theme 
		/// </summary>
		HighContrast = 1,

		/// <summary>
		/// Simple muted theme
		/// </summary>
		Simple = 2,

		/// <summary>
		/// Colorful theme 
		/// </summary>
		Colorful = 3
	}

	#endregion 

	#region Console Color Theme

	public sealed class ConsoleColorTheme
	{
		internal ConsoleColorExt[] Mappings = new ConsoleColorExt[32];

		/// <summary>
		/// Load theme from a file path and for a given background color 
		/// </summary>
		/// <param name="backgroundColour">background color for the theme</param>
		/// <param name="path">the path of the theme to load</param>
		/// <returns>the console theme</returns>
		public static ConsoleColorTheme Load(ConsoleColor backgroundColour, string path)
		{
			ConsoleColorThemeDirectory dir = ConsoleColorThemeDirectory.Read(path);

			return dir[backgroundColour]; 
		}

		/// <summary>
		/// Load theme from a stream and for a given background color 
		/// </summary>
		/// <param name="backgroundColour">background color for the theme</param>
		/// <param name="stream">the stream that contians the color theme</param>
		/// <returns>the console theme</returns>	
		public static ConsoleColorTheme Load(ConsoleColor backgroundColour, Stream stream)
		{
			ConsoleColorThemeDirectory dir = ConsoleColorThemeDirectory.Read(stream);

			return dir[backgroundColour];
		}

		/// <summary>
		/// Load an embeded theme for a given background color 
		/// </summary>
		/// <param name="backgroundColour">background color for the theme</param>
		/// <param name="type">a type in the same assembly and namespace as the theme to load</param>
		/// <param name="path">the name of the embeded color theme</param>
		/// <returns>the console theme</returns>	
		public static ConsoleColorTheme Load(ConsoleColor backgroundColour, Type type, string path)
		{
			Assembly asm = type.Assembly;

			ConsoleColorThemeDirectory dir = ConsoleColorThemeDirectory.Read(asm.GetManifestResourceStream(type, path));

			return dir[backgroundColour];
		}

		/// <summary>
		/// Load a default theme using the current color context 
		/// </summary>
		/// <param name="theme">default theme from the default theme enumeration</param>
		/// <returns>the console theme</returns>	
		public static ConsoleColorTheme Load(ConsoleColorDefaultThemes theme)
		{
			return Load((ConsoleColor)RC.ForegroundColor, (ConsoleColor)RC.BackgroundColor, theme);
		}

		/// <summary>
		/// Load a default theme 
		/// </summary>
		/// <param name="foregroundColour">the foreground color</param>
		/// <param name="backgroundColour">the background color</param>
		/// <param name="theme">the default color theme to load</param>
		/// <returns>the console theme</returns>
		public static ConsoleColorTheme Load(ConsoleColor foregroundColour, ConsoleColor backgroundColour, ConsoleColorDefaultThemes theme)
		{
			Assembly asm = typeof(ConsoleColorTheme).Assembly;
			Stream file; 

			switch (theme)
			{
				case ConsoleColorDefaultThemes.None:
				case ConsoleColorDefaultThemes.HighContrast:
					return new ConsoleColorTheme(foregroundColour, backgroundColour, theme);
				case ConsoleColorDefaultThemes.Simple:
					file = asm.GetManifestResourceStream(typeof(ConsoleColorTheme), "Simple.ctheme");
					return Load(backgroundColour, file); 
				case ConsoleColorDefaultThemes.Colorful:                    
					file = asm.GetManifestResourceStream(typeof(ConsoleColorTheme), "Colorful.ctheme");
					return Load(backgroundColour, file);
				default:
					return new ConsoleColorTheme(foregroundColour, backgroundColour, ConsoleColorDefaultThemes.None);             
			}            
		}

		#region Constructors
		
		public ConsoleColorTheme()
		{

		}
	
		private ConsoleColorTheme(ConsoleColor foregroundColour, ConsoleColor backgroundColour, ConsoleColorDefaultThemes theme)
		{
			switch (theme)
			{
				case ConsoleColorDefaultThemes.None:
					SetNoTheme(foregroundColour, backgroundColour); 
					break;
				case ConsoleColorDefaultThemes.HighContrast:
					SetHighContrastTheme(foregroundColour, backgroundColour);
					break;                
				default:
					break;
			}
		}
		
		#endregion

		#region Console Color Lookup

		/// <summary>
		/// Gets or sets the ConsoleColor for a given ConsoleThemeColor within this theme 
		/// </summary>
		/// <param name="color">the console theme color</param>
		/// <returns>a console color</returns>
		public ConsoleColorExt this[ConsoleThemeColor color]
		{
			get { return Mappings[(int)color]; }
			set { Mappings[(int)color] = value; }
		}

		private ConsoleColorExt GetColor(ConsoleThemeColor color)
		{
			return Mappings[(int)color];
		}

		private ConsoleColor GetConsoleColor(ConsoleColor current, ConsoleThemeColor color)
		{
			ConsoleColorExt col = GetColor(color);

			if (col != ConsoleColorExt.Inhreit)
				return (ConsoleColor)(int)(col);
			else
				return current;
		}

		#endregion

		#region Set No Theme

		private void SetNoTheme(ConsoleColor foregroundColour, ConsoleColor backgroundColour)
		{
			this[ConsoleThemeColor.AppBackground] = (ConsoleColorExt)backgroundColour;
			this[ConsoleThemeColor.PanelBackground] = (ConsoleColorExt)backgroundColour;

			this[ConsoleThemeColor.TitleText] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.TitleText1] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.TitleText2] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.TitleText3] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.Text] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.Text1] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.Text2] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.Text3] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.SubText] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.SubText1] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.SubText2] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.SubText3] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.ErrorColor1] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.ErrorColor2] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.WarningColor1] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.WarningColor2] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.PromptColor1] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.PromptColor2] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.TextGood] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.SubTextGood] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.TextNutral] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.SubTextNutral] = (ConsoleColorExt)foregroundColour;

			this[ConsoleThemeColor.TextBad] = (ConsoleColorExt)foregroundColour;
			this[ConsoleThemeColor.SubTextBad] = (ConsoleColorExt)foregroundColour;
		}        

		#endregion

		#region Set High Contrast Theme

		private void SetHighContrastTheme(ConsoleColor foregroundColour, ConsoleColor backgroundColour)
		{
			switch (backgroundColour)
			{
				case ConsoleColor.Black:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.DarkBlue:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.DarkCyan:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.DarkGreen:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.DarkMagenta:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.DarkRed:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.DarkYellow:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.DarkGray:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);    
					break;
				case ConsoleColor.Gray:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.Blue:
					SetNoTheme(ConsoleColor.Yellow, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.White);
					SetIndicatorColors(ConsoleColor.Yellow, ConsoleColor.Yellow, ConsoleColor.Yellow);
					break;
				case ConsoleColor.Cyan:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.Green:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.Magenta:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Yellow, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.Red:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Yellow, ConsoleColor.Yellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.White:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.DarkYellow, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				case ConsoleColor.Yellow:
					SetNoTheme(foregroundColour, backgroundColour);
					SetMessageColors(ConsoleColor.Red, ConsoleColor.Red, ConsoleColor.Blue);
					SetIndicatorColors(foregroundColour, foregroundColour, foregroundColour);
					break;
				default:
					break;
			}
		}

		#endregion

		#region Set Color Methods

		private void SetMessageColors(ConsoleColor ErrorColor, ConsoleColor WarningColor, ConsoleColor PromptColor)
		{
			SetMessageColors1(ErrorColor, WarningColor, PromptColor);
			SetMessageColors2(ErrorColor, WarningColor, PromptColor);
		}

		private void SetMessageColors1(ConsoleColor ErrorColor1, ConsoleColor WarningColor1, ConsoleColor PromptColor1)
		{
			this[ConsoleThemeColor.ErrorColor1] = (ConsoleColorExt)ErrorColor1;
			this[ConsoleThemeColor.WarningColor1] = (ConsoleColorExt)WarningColor1;
			this[ConsoleThemeColor.PromptColor1] = (ConsoleColorExt)PromptColor1;
		}

		private void SetMessageColors2(ConsoleColor ErrorColor2, ConsoleColor WarningColor2, ConsoleColor PromptColor2)
		{
			this[ConsoleThemeColor.ErrorColor2] = (ConsoleColorExt)ErrorColor2;
			this[ConsoleThemeColor.WarningColor2] = (ConsoleColorExt)WarningColor2;
			this[ConsoleThemeColor.PromptColor2] = (ConsoleColorExt)PromptColor2;
		}

		private void SetIndicatorColors(ConsoleColor Good, ConsoleColor Nutral, ConsoleColor Bad)
		{
			SetIndicatorTextColors(Good, Nutral, Bad);
			SetIndicatorSubTextColors(Good, Nutral, Bad);
		}

		private void SetIndicatorTextColors(ConsoleColor Good, ConsoleColor Nutral, ConsoleColor Bad)
		{
			this[ConsoleThemeColor.TextGood] = (ConsoleColorExt)Good;
			this[ConsoleThemeColor.TextNutral] = (ConsoleColorExt)Nutral;
			this[ConsoleThemeColor.TextBad] = (ConsoleColorExt)Bad;
		}

		private void SetIndicatorSubTextColors(ConsoleColor Good, ConsoleColor Nutral, ConsoleColor Bad)
		{
			this[ConsoleThemeColor.SubTextGood] = (ConsoleColorExt)Good;
			this[ConsoleThemeColor.SubTextNutral] = (ConsoleColorExt)Nutral;
			this[ConsoleThemeColor.SubTextBad] = (ConsoleColorExt)Bad;
		}

		#endregion

	}

	#endregion
}
